
package com.sbtr.business.calibration.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sbtr.business.calibration.entity.*;
import com.sbtr.business.calibration.mapper.CalibrationObjectDetectionMapper;
import com.sbtr.business.calibration.service.ICalibrationObjectDetectionService;
import com.sbtr.business.classify.entity.Classify;
import com.sbtr.business.classify.service.IClassifyService;
import com.sbtr.common.PageDto;
import com.sbtr.constant.CalibrationConstant;
import com.sbtr.open.calibration.dto.*;
import com.sbtr.open.classify.dto.ClassifyDto;
import com.sbtr.util.BeanCopyUtils;
import com.sbtr.util.PageDtoUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * <p>
 * 标定集 服务实现类
 * </p>
 *

 */
@Transactional
@Service
public class CalibrationObjectDetectionServiceImpl extends ServiceImpl<CalibrationObjectDetectionMapper, CalibrationObjectDetection>
		implements ICalibrationObjectDetectionService {

    private static final Logger logger = LoggerFactory.getLogger(CalibrationObjectDetectionServiceImpl.class);
    @Autowired
    private IClassifyService classifyService;
    @Autowired
    private IService<CalibrationObjectDetectionImgBox> imgBoxService;
    @Autowired
//    private IService<CalibrationImg> calibrationImgService;
    private CalibrationImgServiceImpl calibrationImgService;
    @Autowired
//    private IService<CalibrationDetails> calibrationDetailsService;
    private CalibrationDetailsServiceImpl calibrationDetailsService;
    @Autowired
    private IService<Calibration> calibrationService;

    @Autowired
    private IService<CalibrationFile> calibrationFileService;

    @Value("${oss.config.httpPath}")
    private String httpPath;

    //列表查询接口
    @Override
    public PageDto<CalibrationImgDetectDto> getImgDetectList(CalibrationSearchByDetailsDto dto){
        IPage<CalibrationImgDetectDto> page = new Page<CalibrationImgDetectDto>();
        page.setSize(dto.getPageSize());
        page.setCurrent(dto.getPage());

        List<CalibrationImgDetectDto> result = baseMapper.getImgDetectList(page,dto);

        PageDto<CalibrationImgDetectDto> pageDto = PageDtoUtils.getPageDtoByIPage(page, CalibrationImgDetectDto.class);
        //拼接图片完整url
        for (CalibrationImgDto calibrationImgDto: result){
            calibrationImgDto.setRelativePath(httpPath+calibrationImgDto.getRelativePath());
            calibrationImgDto.setThumbnailRelativePath(httpPath+calibrationImgDto.getThumbnailRelativePath());
        }
        pageDto.setList(result);
        return pageDto;
    }

    @Override
    public List<ClassifyDto> loadImgDetectCalibrationAllLabels(Long calibrationDetailsId){

        //CalibrationDetailsDto calibrationDetailsDto = calibrationDetailsService.findById(calibrationDetailsId);

        List<Classify> labels = baseMapper.loadImgDetectCalibrationAllLabels(calibrationDetailsId);

        return BeanCopyUtils.copyProperties(labels, ClassifyDto.class);
        //return labels;
    }

//    @PostMapping("/count-img-hascalibrated")
//    public List<CalibrationCountByClassifyDto> countImgHasCalibrated(@RequestParam("calibrationDetailsId") Long calibrationDetailsId)
//    {
//        CalibrationDetailsDto calibrationDetailsDto = calibrationDetailsService.findById(calibrationDetailsId);
//        String finisher=calibrationDetailsDto.getFinisher();
//        Long calibration_id=calibrationDetailsDto.getCalibrationId();
//
//        List<CalibrationCountByClassifyDto>dtoList=baseMapper.countImgHasCalibrated(finisher,calibration_id);
//        return dtoList;
//    }

//    @PostMapping(value = "/queryImgDetectList")
//    @ResponseBody
//    public PageDto<CalibrationImgDtDto> queryImgDetectList(@RequestBody CalibrationSearchByDetailsDto dto){
//
//        IPage<CalibrationTxt> page = new Page<>();
//        page.setSize(dto.getPageSize());
//        page.setCurrent(dto.getPage());
//        QueryWrapper<CalibrationImgDetectDto> wrapper = new QueryWrapper<>();
//
//        if (null != dto.getId()) {
//            wrapper.eq("calibration_id", dto.getId());
//        }
//        if (null != dto.getFinisher()) {
//            wrapper.eq("finisher", dto.getFinisher());
//        }
//        if (null != dto.getClassifyId()) {
//            wrapper.eq("classify_id", dto.getClassifyId());
//        }
//
//        wrapper.eq("completed", "1");
////		wrapper.orderByDesc("id");
//        page = page(page, wrapper);
//        PageDto<CalibrationTxtDto> pageDto = PageDtoUtils.getPageDtoByIPage(page, CalibrationTxtDto.class);
//        return pageDto;
//
//    }

    /**
     * 加载指定图片上的所有标签和框框坐标信息
     * @param picId  图片id
     */
    @Override
    public List<CalibrationObjectDetectionDto> loadOnePicLabels(String picId){
        QueryWrapper<CalibrationObjectDetection> queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
        queryWrapper.eq("pic_id",picId);

        List<CalibrationObjectDetection> items = this.list(queryWrapper);
        return BeanCopyUtils.copyProperties(items,CalibrationObjectDetectionDto.class);
    }

    /**
     * 删除标签记录和框框坐标
     * @param calibrationId
     * @param picId
     * @param classifyId
     */
    @Override
    public String deleteLable(String calibrationId,String picId,String classifyId){
        QueryWrapper<CalibrationObjectDetection> queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
        queryWrapper.eq("pic_id",picId);
        queryWrapper.eq("calibration_id",calibrationId);
        queryWrapper.eq("classify_id",classifyId);

        this.remove(queryWrapper);

        //检索当前图片是否还有标签记录，没有的话，需要更新CalibrationImg的状态改为未完成；
        queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
        queryWrapper.eq("pic_id",picId);
        List<CalibrationObjectDetection> items = this.list(queryWrapper);
        if(null == items || items.isEmpty()){
            //更新calibrationImg状态--->已完成
            CalibrationImg img = calibrationImgService.getById(picId);
            img.setCompleted("0");//未完成
            calibrationImgService.saveOrUpdate(img);
        }


        return "success";
    }

//    @RequestMapping(value = "loadCompletedPics", method = RequestMethod.GET)
//    public void loadCompletedPics(String calibrationId){
//
//
//    }
//
//
//    @RequestMapping(value = "loadNoCompletedPics", method = RequestMethod.GET)
//    public void loadNoCompletedPics(String calibrationId){
//
//
//    }
    //按照标签加载图片
    @Override
    public List<CalibrationImgDetectDto> queryPicByLabelId (String classifyId){
        return getBaseMapper().queryPicByLabelId(classifyId);
    }


    //批量打标签,一（图片）对多（标签、框框）
    @Override
    public List<CalibrationObjectDetectionDto> batchSaveLabel(List<CalibrationObjectDetectionDto> items,Long picId) {
        List<CalibrationObjectDetectionDto> newList  = new ArrayList<>();

        if(items.isEmpty() && picId != null){//空列表表示清空当前图片的所有标签记录
            QueryWrapper<CalibrationObjectDetection> queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
            queryWrapper.eq("pic_id",picId);
            this.baseMapper.delete(queryWrapper);

            //更新img对象的状态--->未标注
            CalibrationImg img = calibrationImgService.getById(picId);
            img.setCompleted("0");
            calibrationImgService.saveOrUpdate(img);

        }else {
            items.stream().forEach(item -> {

                CalibrationObjectDetectionDto vo = this.save(item);
                newList.add(vo);
            });
        }
        return newList;
    }


    /**
     *  打标签,一（图片）对多（标签、框框）
     *  保存和修改
     */
    @Override
    public CalibrationObjectDetectionDto save(CalibrationObjectDetectionDto dto) {
        //图片id必须带入
        CalibrationObjectDetection data = BeanCopyUtils.copyProperties(dto, CalibrationObjectDetection.class);
        //复制标签属性
        Classify classify = BeanCopyUtils.copyProperties(dto, Classify.class);//作为主任务标签来保存

//        if (dto.getPicId() != null) {
            if(null == dto.getClassifyId()) {//如果没有传递classifyId,则以标签名来查主任务下，有无该名字的标签
                classify.setCalibrationId(dto.getCalibrationId());

                QueryWrapper<Classify> queryWrapper = new QueryWrapper<Classify>();
                queryWrapper.eq("calibration_id", dto.getCalibrationId());
                queryWrapper.eq("classify_name", dto.getClassifyName());
                Classify co = classifyService.getOne(queryWrapper);
                if(co == null) {//没有同名标签，则先新建标签
                    classifyService.save(classify);
                }else{
                    classify = co;//主任务下，已存在，则用之前的标签
                }
            }else{
                classify = classifyService.getById(dto.getClassifyId());//有标签id则加载标签对象
                if(null == classify){
                    throw new IllegalArgumentException("没有找到该标签，classifyId="+dto.getClassifyId());
                }
            }
            if (null != classify) {
                data.setClassifyId(classify.getId());
                data.setClassifyName(classify.getClassifyName());
            }
            data.setCreateTime(new Date());

            save(data);//保存打标签记录
            //更新calibrationImg状态--->已完成
            CalibrationImg img = calibrationImgService.getById(dto.getPicId());
            img.setCompleted("1");//已完成
            img.setFinisher(dto.getCreator());
//            img.setClassifyId(classify.getId());
//            img.setClassifyName(classify.getClassifyName());不是一对一
            calibrationImgService.saveOrUpdate(img);

            //更新每日标注统计
            CalibrationDetailsDto calibrationDetailsDto = calibrationDetailsService.findById(dto.getCalibrationDetailId());
            calibrationImgService.updateCalibrationImgRecordDaily(calibrationDetailsDto);

            /****************************************  更新子任务calibrationDetail状态 ***********************************************/
            if(null != dto.getCalibrationDetailId()) {
                //查询当前任务有多少图片已经打标签----->更新CalibrationDetail
                long nowCompleted = baseMapper.getCompletedCountByCalibrationDetailId(dto.getCalibrationDetailId());
                long nowClassifyCount = baseMapper.getClassifyCountByCalibrationDetailId(dto.getCalibrationDetailId());
                //更新calibrationDetails 中已完成的数目状态--->已完成
                CalibrationDetails details = calibrationDetailsService.getById(dto.getCalibrationDetailId());
                if (details == null) {
                    throw new IllegalArgumentException("找不到CalibrationDetail记录，calibrationDetailId=" + dto.getCalibrationDetailId());
                }

                details.setCompleted((int) nowCompleted);
                details.setClassifyCount((int) nowClassifyCount);
                if (nowCompleted == details.getTotalCount()) {
                    details.setStatus(CalibrationConstant.TASK_STATUS_COMPLETED);
                    details.setFinishedTime(new Date());
                }
                calibrationDetailsService.saveOrUpdate(details);
                logger.info("更新子任务状态成功：{}",JSONObject.toJSONString(details));
            }

            /****************************************  更新主任务calibration状态 ***********************************************/
            if(null != dto.getCalibrationId() ) {
                Calibration calibration = calibrationService.getById(dto.getCalibrationId());
                if(null != calibration){
                    long nowCompleted2 = baseMapper.getCompletedCountByCalibrationId(dto.getCalibrationId());
                    long nowClassifyCount2 = baseMapper.getClassifyCountByCalibrationId(dto.getCalibrationId());

                    calibration.setCompleted((int)nowCompleted2);
                    calibration.setClassifyCount((int)nowClassifyCount2);
                    if(calibration.getCompleted()== calibration.getTotalCount()){
                        calibration.setStatus(CalibrationConstant.TASK_STATUS_COMPLETED);
                    }else{
                        calibration.setStatus(CalibrationConstant.TASK_STATUS_CALIBRATING);
                    }

                    calibrationService.saveOrUpdate(calibration);
                    logger.info("更新主任务状态成功：{}",JSONObject.toJSONString(calibration));
                }
            }

            //查出当前任务下当前图片的所有的标签记录，然后更新图片的所有的坐标信息
            QueryWrapper<CalibrationObjectDetection> queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
            queryWrapper.eq("pic_id", dto.getPicId());

            List<CalibrationObjectDetection> rList = baseMapper.selectList(queryWrapper);
            createOrUpdateCalibrationObjectDetectionImgBox(data,rList);

//        } else {
//            return BeanCopyUtils.copyProperties(data, CalibrationObjectDetectionDto.class);
//        }
        return dto;
    }


    @Override
    public boolean deleteLable(CalibrationObjectDetectionDto dto) {
        QueryWrapper<CalibrationObjectDetection> queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
        queryWrapper.eq("pic_id", dto.getPicId());
        queryWrapper.eq("classify_id", dto.getClassifyId());
        queryWrapper.eq("calibration_detail_id", dto.getCalibrationDetailId());

        try {
            baseMapper.delete(queryWrapper);

            //查询当前图片是否还有标签，如果没有，更新img的标注状态
            queryWrapper = new QueryWrapper<CalibrationObjectDetection>();
            queryWrapper.eq("pic_id", dto.getPicId());
            queryWrapper.eq("calibration_detail_id", dto.getCalibrationDetailId());
            List<CalibrationObjectDetection> list = baseMapper.selectList(queryWrapper);
            if (null == list || list.isEmpty()) {
                CalibrationImg img = calibrationImgService.getById(dto.getPicId());
                img.setCompleted("0");
                calibrationImgService.saveOrUpdate(img);
            }

            //更新每日标注统计
            CalibrationDetailsDto calibrationDetailsDto = calibrationDetailsService.findById(dto.getCalibrationDetailId());
            calibrationImgService.updateCalibrationImgRecordDaily(calibrationDetailsDto);

            //TODO 更新detail 、calibration  的标签数  进度
            /****************************************  更新子任务calibrationDetail状态 ***********************************************/
            if(null != dto.getCalibrationDetailId()) {
                //查询当前任务有多少图片已经打标签----->更新CalibrationDetail
                long nowCompleted = baseMapper.getCompletedCountByCalibrationDetailId(dto.getCalibrationDetailId());
                long nowClassifyCount = baseMapper.getClassifyCountByCalibrationDetailId(dto.getCalibrationDetailId());
                //更新calibrationDetails 中已完成的数目状态--->已完成
                CalibrationDetails details = calibrationDetailsService.getById(dto.getCalibrationDetailId());
                if (details == null) {
                    throw new IllegalArgumentException("找不到CalibrationDetail记录，calibrationDetailId=" + dto.getCalibrationDetailId());
                }

                details.setCompleted((int) nowCompleted);
                details.setClassifyCount((int) nowClassifyCount);
                if (nowCompleted == details.getTotalCount()) {
                    details.setStatus(CalibrationConstant.TASK_STATUS_COMPLETED);
                    details.setFinishedTime(new Date());
                }
                calibrationDetailsService.saveOrUpdate(details);
                logger.info("更新子任务状态成功：{}",JSONObject.toJSONString(details));
            }

            /****************************************  更新主任务calibration状态 ***********************************************/
            if(null != dto.getCalibrationId() ) {
                Calibration calibration = calibrationService.getById(dto.getCalibrationId());
                if(null != calibration){
                    long nowCompleted2 = baseMapper.getCompletedCountByCalibrationId(dto.getCalibrationId());
                    long nowClassifyCount2 = baseMapper.getClassifyCountByCalibrationId(dto.getCalibrationId());

                    calibration.setCompleted((int)nowCompleted2);
                    calibration.setClassifyCount((int)nowClassifyCount2);
                    calibrationService.saveOrUpdate(calibration);
                    logger.info("更新主任务状态成功：{}",JSONObject.toJSONString(calibration));
                }
            }
            return true;
        }catch(Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 新增或更新改图片的CalibrationObjectDetectionImgBox对象
     * @param ob   需要pic_id
     * @param list
     * @return
     */
    @Override
    public CalibrationObjectDetectionImgBox createOrUpdateCalibrationObjectDetectionImgBox(CalibrationObjectDetection ob,List<CalibrationObjectDetection> list)  {
        //先查是不是已存在记录
        QueryWrapper<CalibrationObjectDetectionImgBox> queryWrapper = new QueryWrapper<CalibrationObjectDetectionImgBox>();
        queryWrapper.eq("pic_id",ob.getPicId());
        CalibrationObjectDetectionImgBox box = imgBoxService.getOne(queryWrapper);
        if(null == box) {
            box = new CalibrationObjectDetectionImgBox();
        }
        CalibrationImg img = calibrationImgService.getById(ob.getPicId());//

        QueryWrapper<CalibrationFile> calibrationFileQueryWrapper = new QueryWrapper<CalibrationFile>();
        calibrationFileQueryWrapper.eq("calibration_id", img.getCalibrationId());//表的字段
        CalibrationFile srcFile = calibrationFileService.list(calibrationFileQueryWrapper).get(0);//源上传文件信息

        box.setCalibrationId(ob.getCalibrationId());
        box.setPicId(ob.getPicId());
        box.setFileName(StringUtils.substringAfterLast(img.getPictureDir(),File.separator));
        box.setPicPath(img.getPictureDir());
        box.setBaseDir(srcFile.getBucketDir()+File.separator+srcFile.getFileName2()+"_unzip"+File.separator);

        JSONObject json = new JSONObject();
        StringBuilder sb = new StringBuilder();
        //{'top': '181', 'left': '274', 'width': '52', 'height': '53'}
        JSONArray arr = new JSONArray();
        list.stream().forEach(item -> {
            //TODO  boxArrStr
            String pointStr = formatPoints(item.getPoints());
            sb.append(pointStr).append(";");
            //   json_txt
            JSONObject jo = formatPoints(item.getClassifyName(),item.getPoints());
            arr.add(jo);
        });
        json.put("box",arr);
        json.put("file",box.getFileName());//图片名

        box.setBoxArrStr(sb.toString().substring(0,sb.length()-1));//TODO 有待确定！！
        box.setJsonTxt(json.toJSONString());

        imgBoxService.saveOrUpdate(box);
        String jsontxtPath = srcFile.getBucketDir()+File.separator +"json.txt";
        File jsontxt = new File(jsontxtPath);
        try {
            if (!jsontxt.exists()) {
                jsontxt.createNewFile();
            }

            //同步更新json.txt文件
            flushJsonTxt(box.getCalibrationId());
        }catch (IOException e){
            e.printStackTrace();
        }

        return box;
    }



    public String formatPoints(String pointStr) {

        //TODO 格式化坐标点  (4.74,2.97)|(22.85,25.28)

        return pointStr;
    }

    public JSONObject formatPoints(String label,String pointStr) {
        String[] tem = pointStr.split("\\|");
        String[] pointA = tem[0].replace("(","").replace(")","").split(",");
        String[] pointB = tem[1].replace("(","").replace(")","").split(",");
        Float left = Float.parseFloat(pointA[0]);
        Float top = Float.parseFloat(pointA[1]);

        Float right = Float.parseFloat(pointB[0]);
        Float bottom = Float.parseFloat(pointB[1]);

        //TODO 格式化坐标点  (4.74,2.97)|(22.85,25.28)
        JSONObject jo = new JSONObject();
        jo.put("label",label);
        jo.put("top",top);
        jo.put("left",left);
        jo.put("height",bottom-top);
        jo.put("width",right-left);
logger.info("生成point json:{}",jo.toString());
        return jo;
    }

    /**
     * 查出任务下的所有CalibrationObjectDetectionImgBox，
     * 生成任务所需的json.txt文件
     * @param calibrationId
     * @throws IOException
     */
    public void flushJsonTxt(long calibrationId) throws IOException {
//        CalibrationObjectDetectionImgBox img = imgBoxService.getById(id);
        QueryWrapper<CalibrationObjectDetectionImgBox> queryWrapper = new QueryWrapper<CalibrationObjectDetectionImgBox>();
        queryWrapper.eq("calibration_id", calibrationId);
        List<CalibrationObjectDetectionImgBox> imgs = imgBoxService.list(queryWrapper);

        StringBuilder sb = new StringBuilder();
        List<String> datas = new ArrayList<>();
        String jsontxtPath = imgs.get(0).getBaseDir() + "json.txt";
        imgs.stream().forEach(item -> {
            //sb.append(item.getJsonTxt());
            datas.add(item.getJsonTxt());
        });
        File file = new File(jsontxtPath);
        if(!file.exists()){
            file.createNewFile();
        }
        try(FileOutputStream fos = new FileOutputStream(file)) {
            IOUtils.writeLines(datas,"\n", fos);
        }
    }


    @Override
	public CalibrationObjectDetectionDto findById(Long id) {
		return BeanCopyUtils.copyProperties(getById(id), CalibrationObjectDetectionDto.class);
	}


}